/*---------------------------------------------------------------------------*
 * Copyright (C) 2011-2014 Ryan M. Murphy <ryan.m.murphy.77@gmail.com>
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * File Name   : usr_consoleBms.c
 *
 * Project     : Watts-rock
 *               <http://code.google.com/p/watts-rock-motherboard/>
 *
 * Description : This file is responsible for command and control over the
 *               console module from a user-space perspective.
 *
 * Programmer  : Ryan M Murphy
 *
 * Last Update : Jan 4, 2014
 *---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*
 * Include Files
 *---------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "arb_error.h"
#include "arb_thread.h"
#include "arb_semaphore.h"
#include "arb_device.h"
#include "arb_sysTimer.h"
#include "arb_console.h"
#include "arb_printf.h"
#include "drv_console.h"
#include "drv_wifly.h"
#include "usr_bms.h"

typedef struct
{
   /*------------------------------------------------------------------------*
    * This variable provides access to the wifi module.
    *------------------------------------------------------------------------*/
   t_DEVHANDLE t_wiflyHndl;

}t_usrObject;

/*---------------------------------------------------------------------------*
 * Private Global Variables
 *---------------------------------------------------------------------------*/
static t_usrObject gt_userObject = {0};

/*---------------------------------------------------------------------------*
 * Private Function Definitions
 *---------------------------------------------------------------------------*/
static void usr_displayUserHelp( t_DEVHANDLE t_consoleHndl,
                                 int8_t *pc_buff)
{
   uint16_t s_size;

   /*------------------------------------------------------------------------*
    * Display a list of all the possible console commands specific
    * to a user-space application.
    *------------------------------------------------------------------------*/
   s_size = sprintf_P( (char *)pc_buff, PSTR(".-------------------------------------------------------------------------.\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| Command |     Arguments      |              Description                 |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|---------|--------------------|------------------------------------------|\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| sbl     |<arg1> <arg2> <arg3>| Configure the battery limits, where      |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |<arg4> <arg5> <arg6>| <arg1> = low volts threshold, <arg2> =   |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | high volts threshold, <arg3> = high      |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | current threshold, <arg4> = high temp    |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | threshold, <arg5> = battery amp-hrs.     |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | <arg6> = max charge current.             |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| gbl     |                    | Queries the BMS limits                   |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| pac     | <arg1>             | Turns on/off the battery output, where   |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | <arg1> = 0, 1 (off, on).                 |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| fan     | <arg1>             | Turns on/off the fan, where              |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | <arg1> = 0, 1 (off, on).                 |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| scc     | <arg1>             | Sets the coloumb count, where            |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("|         |                    | 0 <= <arg1> =< 100.                      |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("| wcm     |                    | Enters Wifly configuration mode          |\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);
   s_size = sprintf_P( (char *)pc_buff, PSTR("'---------'--------------------'------------------------------------------'\n\r"));
   arb_write( t_consoleHndl,
              pc_buff,
              s_size);

}/*End usr_displayUserHelp*/

/*---------------------------------------------------------------------------*
 * Public Function Definitions
 *---------------------------------------------------------------------------*/
bool usr_console( t_DEVHANDLE t_consoleHndl,
                  int8_t *pc_buff,
                  t_consoleTokHndl *pt_tokHndl)
{
   bool b_success = true; /*A valid command was found.*/
   uint16_t s_size;

   if( gt_userObject.t_wiflyHndl == 0)
   {
      gt_userObject.t_wiflyHndl = arb_open( "wiflyDevice0",
                                            ARB_O_READ |
                                            ARB_O_WRITE);

      if( gt_userObject.t_wiflyHndl < 0)
         exit(0);

   }/*End if( gt_userObject.t_wiflyHndl == 0)*/

   if( strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("hlpu")) == 0)
   {
      /*---------------------------------------------------------------------*
       * Display a list of all the possible user-space specific commands.
       *---------------------------------------------------------------------*/
      usr_displayUserHelp( t_consoleHndl,
                           pc_buff);

   }/*End else if( strcmp( (char *)pt_tokHndl->ac_tok[0], "hlpu") == 0)*/
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("sbl")) == 0)
   && (pt_tokHndl->c_numTokens == 7))
   {
      int16_t s_numBytes;
      t_bmsSetLimitsMsg t_setLimits;
      t_MAILBOXHNDL t_bmsMlbxHndl = usr_getBmsInMlbxHndle();

      t_setLimits.c_msgId = BMS_CMD_SET_LIMITS;

      t_setLimits.t_limits.f_lowVoltageThr = atof( (char *)&pt_tokHndl->ac_tok[1][0]);
      t_setLimits.t_limits.f_highVoltageThr = atof( (char *)&pt_tokHndl->ac_tok[2][0]);
      t_setLimits.t_limits.f_highCurrThr = atof( (char *)&pt_tokHndl->ac_tok[3][0]);
      t_setLimits.t_limits.f_highTempThr = atof( (char *)&pt_tokHndl->ac_tok[4][0]);
      t_setLimits.t_limits.f_battAmpHours = atof( (char *)&pt_tokHndl->ac_tok[5][0]);
      t_setLimits.t_limits.f_maxChargeCurrent = atof( (char *)&pt_tokHndl->ac_tok[6][0]);

      s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
                                    (int8_t *)&t_setLimits,
                                    (int16_t)sizeof( t_setLimits));

      /*---------------------------------------------------------------------*
       * Wait for acknowledgment...
       *---------------------------------------------------------------------*/
   }
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("gbl")) == 0))
   {
      t_bmsLimits *pt_bmsLim;

      pt_bmsLim = usr_getBmsLimits(); 

      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery amp-hours................%2.2f\n\r"),
      pt_bmsLim->f_battAmpHours);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery low voltage threshold....%2.2f\n\r"),
      pt_bmsLim->f_lowVoltageThr);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery high voltage threshold...%2.2f\n\r"),
      pt_bmsLim->f_highVoltageThr);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery high current threshold...%2.2f\n\r"),
      pt_bmsLim->f_highCurrThr);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery high temp threshold......%2.2f\n\r"),
      pt_bmsLim->f_highTempThr);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
      s_size = sprintf_P( (char *)pc_buff, PSTR("Battery max charge current.......%2.2f\n\r"),
      pt_bmsLim->f_maxChargeCurrent);
      arb_write( t_consoleHndl,
                 pc_buff,
                 s_size);
   }
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("pac")) == 0)
   && (pt_tokHndl->c_numTokens == 2))
   {
      int16_t s_numBytes;
      t_MAILBOXHNDL t_bmsMlbxHndl = usr_getBmsInMlbxHndle();
      t_bmsPacCntrlMsg t_pacCntl;

      t_pacCntl.c_msgId = BMS_CMD_PACK_CNTRL;

      if( pt_tokHndl->ac_tok[1][0] == '0')
      {
         t_pacCntl.b_enabled = false;
         s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
                                        (int8_t *)&t_pacCntl,
                                        (int16_t)sizeof( t_bmsPacCntrlMsg));

      }
      else if( pt_tokHndl->ac_tok[1][0] == '1')
      {
         t_pacCntl.b_enabled = true;
         s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
                                        (int8_t *)&t_pacCntl,
                                        (int16_t)sizeof( t_bmsPacCntrlMsg));

      }
      else
      {
         s_size = sprintf_P( (char *)pc_buff, PSTR("Invalid argument\n\r"));
         arb_write( t_consoleHndl,
                    pc_buff,
                    s_size);
      }

   }
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("fan")) == 0)
   && (pt_tokHndl->c_numTokens == 2))
   {
      int16_t s_numBytes;
      t_MAILBOXHNDL t_bmsMlbxHndl = usr_getBmsInMlbxHndle();
      t_bmsFanCntrlMsg t_fanCntl;

      t_fanCntl.c_msgId = BMS_CMD_FAN_CNTRL;

      if( pt_tokHndl->ac_tok[1][0] == '0')
      {
         t_fanCntl.b_enabled = false;
         s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
         (int8_t *)&t_fanCntl,
         (int16_t)sizeof( t_bmsFanCntrlMsg));

      }
      else if( pt_tokHndl->ac_tok[1][0] == '1')
      {
         t_fanCntl.b_enabled = true;
         s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
         (int8_t *)&t_fanCntl,
         (int16_t)sizeof( t_bmsFanCntrlMsg));

      }
      else
      {
         s_size = sprintf_P( (char *)pc_buff, PSTR("Invalid argument\n\r"));
         arb_write( t_consoleHndl,
         pc_buff,
         s_size);
      }

   }
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("scc")) == 0)
   && (pt_tokHndl->c_numTokens == 2)) /*Set coloumb count*/
   {
      int16_t s_numBytes;
      t_bmsSetCmbCntMsg t_setCmbCnt;
      t_MAILBOXHNDL t_bmsMlbxHndl = usr_getBmsInMlbxHndle();

      t_setCmbCnt.c_msgId = BMS_CMD_SET_CMB_CNT;
      t_setCmbCnt.f_percFull = atof( (char *)&pt_tokHndl->ac_tok[1][0]);

      s_numBytes = arb_mailboxWrite( t_bmsMlbxHndl,
                                    (int8_t *)&t_setCmbCnt,
                                    (int16_t)sizeof( t_setCmbCnt));

      /*---------------------------------------------------------------------*
       * Wait for acknowledgment...
       *---------------------------------------------------------------------*/
   }
   else if( (strcmp_P( (char *)pt_tokHndl->ac_tok[0], PSTR("wcm")) == 0)
   && (pt_tokHndl->c_numTokens == 1)) /*Enter Wifly configuration mode*/
   {
      t_wiflyError t_err;
      int16_t s_size;

      t_err = (t_wiflyError)arb_ioctl( gt_userObject.t_wiflyHndl,
                                       WIFLY_ENTER_CMD,
                                       0);

      if( t_err == WIFLY_PASSED)
      {
         do
         {

            s_size = arb_read( t_consoleHndl,
                               (int8_t *)pc_buff,
                               (uint16_t)MAX_CONSOLE_BUFF_SIZE);

            if( s_size > 0)
            {

               s_size = (int16_t)arb_ioctl( gt_userObject.t_wiflyHndl,
                                            WIFLY_SEND_CMD,
                                            (uint32_t)((uint16_t)pc_buff));
            }

         }while ( strncmp_P( (const char *)pc_buff, PSTR("exit"), 4) != 0);

         t_err = (t_wiflyError)arb_ioctl( gt_userObject.t_wiflyHndl,
                                          WIFLY_EXIT_CMD,
                                          0);

      }/*End if( t_err == WIFLY_PASSED)*/
   }
   else /*Unrecognized message*/
   {
      /*---------------------------------------------------------------------*
       * Let 'arb_console' know the command wasn't found.
       *---------------------------------------------------------------------*/
      b_success = false;
   }

   /*------------------------------------------------------------------------*
    * Return control over the console to the kernel...
    *------------------------------------------------------------------------*/
   return b_success;

}/*End usr_console*/
